<template>
  <demo-content :title="title">
    <p>点击 snapshot 在 canvas 上覆盖一个 img 元素，允许图片保存。</p>
    <p>
      这里主要用到 <code>canvas.toDataUrl()</code> 将 canvas 转换为一个 base64
      的 image url。
    </p>
    <div style="margin-bottom: 10px">
      <button @click="showSnapshot = !showSnapshot">
        {{ showSnapshot ? "restore" : "snapshot" }}
      </button>
    </div>
    <div style="position: relative">
      <img
        style="position: absolute; width: 150px; height: 150px"
        :style="imgStyle"
        :src="imgSrc"
      />
      <canvas
        width="150"
        ref="canvasRef"
        style="background-color: white"
      ></canvas>
    </div>
  </demo-content>
</template>

<script setup lang="ts">
import { onMounted, ref } from "vue";
import { computed } from "vue";
import { watch } from "vue";

const title = "打印 Canvas 的内容";
// 指定组件上的属性
defineOptions({ title });

const canvasRef = ref<HTMLCanvasElement>();

function calcPos(centerX: number, centerY: number, r: number, angle: number) {
  const x = Math.cos(angle) * r + centerX;
  const y = Math.sin(angle) * r + centerY;
  return { x, y };
}

setInterval(updateTime, 1000);
let canvas: HTMLCanvasElement;
// 快照相关操作
const showSnapshot = ref(false);
const imgStyle = computed(() => ({
  display: showSnapshot.value ? "inline" : "none",
}));
const imgSrc = ref("");
watch(showSnapshot, (nv) => {
  if (nv) {
    imgSrc.value = canvas.toDataURL();
  }
});

function updateTime() {
  canvas = canvasRef.value!;
  if (!canvas) return;
  if (showSnapshot.value) return;
  const ctx = canvas.getContext("2d")!;
  ctx.beginPath();
  const midX = 75;
  const midY = 75;
  ctx.clearRect(0, 0, 300, 150);
  const r = 60;
  // 时钟轮廓(空心圆)
  ctx.arc(midX, midY, r, 0, 2 * Math.PI);
  ctx.stroke();
  ctx.closePath();

  // 中心点(实心圆)
  ctx.beginPath();
  ctx.arc(midX, midY, 3, 0, 2 * Math.PI);
  ctx.fill();
  ctx.stroke();
  ctx.closePath();

  // 时钟刻度
  for (let i = 1; i < 13; ++i) {
    const tr = r + 8;
    const lr = r - 4;
    const cosV = Math.cos((i * Math.PI) / 6);
    const sinV = Math.sin((i * Math.PI) / 6);
    const px = cosV * tr;
    const py = sinV * tr;
    const lx0 = cosV * lr + midX;
    const ly0 = sinV * lr + midY;
    const lx1 = cosV * (lr + 4) + midX;
    const ly1 = sinV * (lr + 4) + midY;
    ctx.beginPath();
    ctx.fillText((((i + 2) % 12) + 1).toString(), px + midX - 3, py + midY + 4);
    ctx.moveTo(lx0, ly0);
    ctx.lineTo(lx1, ly1);
    ctx.stroke();
    ctx.closePath();
  }
  const now = new Date();
  // 计算时间
  console.log(`${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`);
  // 绘制时针
  const hourAngle =
    (now.getHours() + now.getMinutes() / 60) * (Math.PI / 6) - Math.PI / 2;
  const hourPos = calcPos(midX, midY, r - 20, hourAngle);
  ctx.beginPath();
  ctx.moveTo(midX, midY);
  ctx.lineTo(hourPos.x, hourPos.y);
  ctx.save();
  ctx.lineWidth = 5;
  ctx.stroke();
  ctx.restore();
  ctx.closePath();
  // 绘制分针
  const minuteAngle =
    (now.getMinutes() + now.getSeconds() / 60) * (Math.PI / 30) - Math.PI / 2;
  const minutePos = calcPos(midX, midY, r - 15, minuteAngle);
  ctx.beginPath();
  ctx.moveTo(midX, midY);
  ctx.lineTo(minutePos.x, minutePos.y);
  ctx.save();
  ctx.lineWidth = 3;
  ctx.stroke();
  ctx.restore();
  ctx.closePath();
  // 绘制秒针
  const secondAngle = now.getSeconds() * (Math.PI / 30) - Math.PI / 2;
  const secondPos = calcPos(midX, midY, r - 8, secondAngle);
  ctx.beginPath();
  ctx.moveTo(midX, midY);
  ctx.lineTo(secondPos.x, secondPos.y);
  ctx.save();
  ctx.lineWidth = 1;
  ctx.stroke();
  ctx.restore();
  ctx.closePath();
}
onMounted(updateTime);
</script>

<style scoped></style>
